package ru.mcfr.oxygen.framework.operations;

import ro.sync.ecss.extensions.api.*;
import ro.sync.ecss.extensions.api.node.AttrValue;
import ro.sync.ecss.extensions.api.node.AuthorDocumentFragment;
import ro.sync.ecss.extensions.api.node.AuthorElement;
import ro.sync.ecss.extensions.api.node.AuthorNode;

import javax.swing.text.BadLocationException;
import java.util.HashMap;
import java.util.Map;

/**
 * Created by IntelliJ IDEA.
 * User: ws
 * Date: 17.05.11
 * Time: 16:41
 * To change this template use File | Settings | File Templates.
 */
abstract public class McfrBaseAuthorOperation implements AuthorOperation{

    protected AuthorAccess authorAccess = null;
    protected ArgumentsMap argumentsMap = null;
    protected AuthorDocumentController controller = null;

    protected boolean selectionMode = false;
    protected AuthorDocumentFragment selectedFragment = null;

    protected int caretPosition = 0;
    protected int startCaretPosition = 0;
    protected int endCaretPosition = 0;

    protected AuthorNode selectedElement = null;

    protected String description;

    protected String[] argumentsNameArray;
    protected Object[] argumentsTypesArray;
    protected String[] argumentsDescriptionsArray;

    public void setAttrValue(Object ae, String attribute, String value){
        if (value == null)
            controller.removeAttribute(attribute, (AuthorElement) ae);
        else
            controller.setAttribute(attribute, new AttrValue(value), (AuthorElement) ae);
    }

    public AuthorElement node2element(AuthorNode an){ return (AuthorElement) an; }
    public AuthorNode element2node(AuthorElement ae) { return (AuthorNode) ae; }

    protected Map<String,String> argumentsValues = new HashMap<String,String>();

    //parse and pack two strings into map -> to 'key:value' presentation
    public Map<String, String> parse(String keys, String values, String separator) {

        Map<String, String> map = new HashMap<String, String>();
        String[] arKeys = keys.split("\\" + separator);

        if (values.isEmpty()){
            for (String cKey : arKeys)
                if (!cKey.isEmpty())
                    map.put(cKey, "");

            return map;
        }

        String[] arValues = values.split("\\" + separator);

        int cKeyId = 0;
        for (String cKey : arKeys) {
            String cVal = "";
            if (cKeyId < arValues.length) cVal = arValues[cKeyId++];
            if (!cKey.isEmpty())
                map.put(cKey, cVal);
        }

        return map;
    }

    public Map<String, String> parse(String keys, String values) {
        return parse(keys, values, ",");
    }

    //make attribute line from two lines by pattern [key(0)]="[value(0)]"
    public String makeAttrBlock(String keys, String values){

        if (keys == null) return "";

        Map<String, String> attrs = parse(keys, values);

        String attrString = "";
        for (String attr : attrs.keySet())
            attrString += attr + "=\"" + attrs.get(attr) + "\" ";

        if (attrString.isEmpty())
            return "";

        return attrString.substring(0, attrString.length() - 1);
    }

    public String getBorderInfoForCell(int x, int y) {
        String key = "";

        if (x == 0 & y == 0)
            key = "ltbr";

        if (x == 0 & y > 0)
            key = "tbr";

        if (x > 0 & y == 0)
            key = "lbr";

        if (x > 0 & y > 0)
            key = "br";

        String border = "";

        if (key.contains("l"))
            border += "border-left,";

        if (key.contains("r"))
            border += "border-right,";

        if (key.contains("t"))
            border += "border-top,";

        if (key.contains("b"))
            border += "border-bottom,";

        int size = border.length();
        if (size > 0)
            return border.substring(0, size - 1);
        else
            return "";
    }

    private void initOperation(){
        //pack arguments from ArgumentsMap to Map;
        for (String arg : this.argumentsNameArray)
            try{
                String value = argumentsMap.getArgumentValue(arg).toString();
                this.argumentsValues.put(arg,value);
            } catch (Exception e){
                this.argumentsValues.put(arg,null);
            }
        //init local variables
        this.controller = this.authorAccess.getDocumentController();
        this.caretPosition = this.authorAccess.getEditorAccess().getCaretOffset();
        this.startCaretPosition = this.authorAccess.getEditorAccess().getSelectionStart();
        this.endCaretPosition = this.authorAccess.getEditorAccess().getSelectionEnd();
        if (this.startCaretPosition < this.endCaretPosition || !this.authorAccess.getEditorAccess().getSelectedText().isEmpty())
            this.selectionMode = true;
        try {
            this.selectedElement = this.controller.getNodeAtOffset(this.caretPosition);
        } catch (BadLocationException e) {
            this.selectedElement = null;
        }
        try {
            this.selectedFragment = this.controller.createDocumentFragment(this.startCaretPosition,endCaretPosition);
        } catch (BadLocationException e) {
            this.selectedFragment = null;
        }
    }

    public abstract void doMainOperation();

    public abstract void doOperationWithSelected() throws AuthorOperationException, BadLocationException;

    public abstract void doOperationAtCaretPos() throws AuthorOperationException;

    public void doOperation(AuthorAccess author_access, ArgumentsMap arguments_map) throws IllegalArgumentException, AuthorOperationException {
        this.authorAccess = author_access;
        this.argumentsMap = arguments_map;

        initOperation();

        controller.beginCompoundEdit();

        try{
            doMainOperation();
            if (selectionMode)
                doOperationWithSelected();
            else
                doOperationAtCaretPos();
        } catch (Exception e){
            authorAccess.getWorkspaceAccess().showErrorMessage("Операция выполнена с ошибкой: " + e.getLocalizedMessage());
        } finally {
            controller.endCompoundEdit();
        }
    }

    public ArgumentDescriptor[] getArguments() {

        ArgumentDescriptor[] res = new ArgumentDescriptor[argumentsNameArray.length];

        for (int i = 0; i < argumentsNameArray.length; i++)
            res[i] = new ArgumentDescriptor(argumentsNameArray[i], (Integer) argumentsTypesArray[i], argumentsDescriptionsArray[i]);

        return res;
    }

    public String getDescription() {
        return description;
    }

}
